//蛇
import {AcGameObject} from "@/assets/scripts/AcGameObject";
import {Cell} from "@/assets/scripts/Cell";

export class Snake extends AcGameObject {
    constructor(info, gamemap) {    //info表示蛇的信息、gamemap表示地图的信息
        super();

        this.id = info.id;
        this.color = info.color;
        this.gamemap = gamemap;

        this.cells = [new Cell(info.r, info.c)];    //存放蛇的身体,cells0存放蛇头
        this.next_cell = null;                      //下一步的目标位置

        this.speed = 5;         // 蛇每秒走5个格子
        this.direction = -1;    // -1表示没有指令，0、1、2、3表示上右下左
        this.status = "idle";   // idle表示静止，move表示正在移动，die表示死亡

        this.dr = [-1, 0, 1, 0];
        this.dc = [0, 1, 0, -1];

        this.step = 0;             //回合数
        this.eps = 1e-2;           // 允许的误差

        this.eye_direction = 0;     //蛇眼睛的方向(左下角的蛇初始朝上,右上角的蛇朝下)
        if (this.id == 1) this.eye_direction = 2;

        //蛇眼睛不同方向的偏移量(两只眼睛[所以x数组有两个])
        this.eye_dx = [[-1, 1], [1, 1], [1, -1], [-1, -1]];
        this.eye_dy = [[-1, -1], [-1, 1], [1, 1], [1, -1]];
    }

    start() {

    }

    //设置方向
    set_direction(d) {
        this.direction = d;
    }

    // 检测当前回合，蛇的长度是否增加[1~10],[13, 16, 19, 22, 25]
    check_tail_increasing() {
        if (this.step <= 10) return true;
        if (this.step % 3 === 1) return true;
        return false;
    }

    //将蛇的状态变为走下一步
    next_step() {
        const d = this.direction;
        this.next_cell = new Cell(this.cells[0].r + this.dr[d], this.cells[0].c + this.dc[d]);

        this.direction = -1;  // 清空操作
        this.status = "move";
        this.step++;

        this.eye_direction = d;     //更新蛇眼睛的方向

        const k = this.cells.length;
        for (let i = k; i > 0; i--)
            this.cells[i] = JSON.parse(JSON.stringify(this.cells[i - 1]));
    }

    //控制蛇的移动
    update_move() {
        const dx = this.next_cell.x - this.cells[0].x;
        const dy = this.next_cell.y - this.cells[0].y;
        const distance = Math.sqrt(dx * dx + dy * dy);      //欧几里得距离

        if (distance < this.eps)         //走到目标点了
        {
            this.status = "idle";       //走完了,停下来
            this.cells[0] = JSON.parse(JSON.stringify(this.next_cell)); //定义一个新蛇头
            this.next_cell = null;

            //如果发现蛇没有变长,砍掉蛇尾
            if (!this.check_tail_increasing())
                this.cells.pop();
        } else {
            // 每两帧之间走的距离(速度乘以时间)
            const move_distance = this.speed * this.timedelta / 1000;
            this.cells[0].x += move_distance * dx / distance;
            this.cells[0].y += move_distance * dy / distance;

            //判断当前蛇尾是否需要变长(不变长就移动[因为加了蛇头了])
            if (!this.check_tail_increasing()) {
                const k = this.cells.length;
                const tail = this.cells[k - 1], tail_target = this.cells[k - 2];
                const tail_dx = tail_target.x - tail.x;
                const tail_dy = tail_target.y - tail.y;
                tail.x += move_distance * tail_dx / distance;
                tail.y += move_distance * tail_dy / distance;
            }
        }
    }

    update() {
        if (this.status === "move") {
            this.update_move();
        }
        this.render();
    }

    render() {
        /**
         * 测试画圆
         * */
        const L = this.gamemap.L;
        const ctx = this.gamemap.ctx;

        //画蛇
        ctx.fillStyle = this.color;
        if (this.status === "die") {            //如果蛇已经死亡,切换颜色
            ctx.fillStyle = "#f5f3f3";
        }

        for (const cell of this.cells) {
            ctx.beginPath();
            ctx.arc(cell.x * L, cell.y * L, L / 2 * 0.8, 0, 2 * Math.PI);
            ctx.fill()
        }

        //蛇的润色(上面都是画圆圈,蛇身之间分隔开了)
        for (let i = 1; i < this.cells.length; i++) {
            const a = this.cells[i - 1], b = this.cells[i];
            if (Math.abs(a.x - b.x) < this.eps && Math.abs(a.y - b.y) < this.eps) continue;
            if (Math.abs(a.x - b.x) < this.eps)         //垂直情况(缩短10 %)
                ctx.fillRect((a.x - 0.5 + 0.1) * L, Math.min(a.y, b.y) * L, L * 0.8, Math.abs(a.y - b.y) * L);
            else                                          //水平计算
                ctx.fillRect(Math.min(a.x, b.x) * L, (a.y - 0.5 + 0.1) * L, Math.abs(a.x - b.x) * L, L * 0.8);
        }

        //绘制蛇的眼睛(2只眼睛)
        ctx.fillStyle = "black";
        for (let i = 0; i < 2; i++) {

            //绝对距离 = (相对距离) * L
            const eye_x = (this.cells[0].x + this.eye_dx[this.eye_direction][i] * 0.15) * L;
            const eye_y = (this.cells[0].y + this.eye_dy[this.eye_direction][i] * 0.15) * L;

            ctx.beginPath();
            ctx.arc(eye_x, eye_y, L * 0.05, 0, 2 * Math.PI);
            ctx.fill();
        }
    }
}